<template>
  <div>
    <el-dialog v-model="showDialog" :title="title" width="40%" center>
      <el-form :model="roleDTO" ref="roleDTORef" :label-width="100" label-position="left">
        <el-form-item label="角色编码" prop="roleCode" :rules="[required, lowercaseLetterOrUnderline]">
          <el-input v-model="roleDTO.roleCode" placeholder="角色编码" clearable />
        </el-form-item>
        <el-form-item label="角色名称" prop="roleName" :rules="required">
          <el-input v-model="roleDTO.roleName" placeholder="角色名称" clearable />
        </el-form-item>
        <el-form-item label="角色描述" prop="roleDesc" :rules="required">
          <el-input type="textarea" v-model="roleDTO.roleDesc" placeholder="角色描述" />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="cancelEdit()"> 取 消 </el-button>
          <el-button type="primary" @click="submitData">提 交</el-button>
        </span>
      </template>
    </el-dialog>
    <el-dialog v-model="showSetAuthDialog" title="设置权限" width="40%" center>
      <div class="flex-container flex-row-between txt-gray-80 txt-0_8em">
        <div class="flex-2">菜单</div>
        <div class="flex-1">按钮和接口</div>
      </div>
      <div class="flex-container flex-row-between">
        <div class="flex-2 menu-tree">
          <el-tree
            default-expand-all
            :data="authorityList"
            :props="{ label: 'authName' }"
            @check-change="authChecked"
            node-key="id"
            ref="authTreeRef"
            show-checkbox>
            <template #default="{ data }">
              <span @click="findSubApiButtonAuth(data.id)">
                <span class="pl-0_3em"> {{ data.authName }}</span>
              </span>
            </template>
          </el-tree>
        </div>
        <div class="flex-1 pl-1em api-button-checkbox">
          <div v-if="subApiButtonAuthList.length > 0">
            <div v-for="item in subApiButtonAuthList" :key="item.id">
              <el-checkbox @change="changeApiButtonAuth(item.id)" :checked="checkedApiButton(item.id)">
                <div class="flex-container flex-row-left">
                  <Dictionary dict-code="AuthType" mode="icon" :item-value="item.authType" />
                  <span>{{ item.authName }}</span>
                </div>
              </el-checkbox>
            </div>
          </div>
          <div v-else>
            <span class="txt-gray-90 txt-0_95em">无</span>
          </div>
        </div>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="cancelEdit()"> 取 消 </el-button>
          <el-button type="primary" @click="submitAuthList">提 交</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, onMounted, computed, nextTick } from 'vue'
import Role from '@/api/sys/role'
import Auth from '@/api/sys/auth'
import { isNotEmpty } from '@/utils/validate'
import { lowercaseLetterOrUnderline, required } from '@/utils/FormRule'
import AuthTypeEnum from '@/enums/AuthTypeEnum'
import useStore from '@/store'
import router from '@/router'
import Dictionary from '@/components/Dictionary/index.vue'

const { user, permission } = useStore()

onMounted(() => {
  Auth.list({ authType: AuthTypeEnum.MENU.value }).then(({ result }) => {
    authorityList.value = result
  })
  Auth.findApiButtonAuth().then(({ result }) => {
    apiButtonAuthList.value = result
  })
})

// 所有的权限列表
const authorityList = ref([])

// 角色参数
const roleDTO = ref({})

// 该角色拥有的权限集合
const authListOfRole = ref([])

// 修改权限选中状态
function authChecked(data, checked, childrenChecked) {
  // 如果选中该节点就将该节点以及子节点加入到角色中
  if (checked) {
    checkedWithLeaf(data, checked)
    findSubApiButtonAuth(data.id)
  } else {
    // 取消的时候如果子节点有选中就添加该节点
    if (childrenChecked) {
      deduplicatePushAuth(data.id)
    } else {
      // 子节点没有被选中的就递归删除
      checkedWithLeaf(data, checked)
    }
  }
}

// 无重复添加
function deduplicatePushAuth(authId) {
  if (!roleDTO.value.authList.includes(authId)) {
    roleDTO.value.authList.push(authId)
  }
}

/**
 * 递归权限节点以及子节点, 进行添加或删除
 * @param data 节点数据
 * @param add  true添加到角色中，false从角色中删除
 */
function checkedWithLeaf(data, add) {
  if (add) {
    deduplicatePushAuth(data.id)
  } else {
    roleDTO.value.authList = roleDTO.value.authList.filter((id) => id !== data.id)
  }
  if (isNotEmpty(data.children)) {
    data.children.forEach((item) => {
      checkedWithLeaf(item, add)
    })
  }
}

// 所有的API或者按钮权限集合
const apiButtonAuthList = ref([])

// 某个菜单下的按钮与API权限
const subApiButtonAuthList = ref([])

// 找出该菜单下的API和Button权限
function findSubApiButtonAuth(parentId) {
  subApiButtonAuthList.value = apiButtonAuthList.value.filter((auth) => auth.parentId === parentId)
}

// 判断API或者按钮是否默认选中
function checkedApiButton(authId) {
  return roleDTO.value.authList && roleDTO.value.authList.includes(authId)
}

// API和Button权限选中触发
function changeApiButtonAuth(authId) {
  if (!roleDTO.value.authList.includes(authId)) {
    roleDTO.value.authList.push(authId)
  } else {
    roleDTO.value.authList = roleDTO.value.authList.filter((id) => id !== authId)
  }
}

// 声明 修改或者新增成功事件
const emits = defineEmits(['success'])

// 表单Form
const roleDTORef = ref()

// 新增一个角色
function add() {
  roleDTORef.value.validate(async (valid) => {
    if (valid) {
      await Role.create(roleDTO.value)
      emits('success')
      cancelEdit()
    }
  })
}

// 更新角色信息
function updateById() {
  roleDTORef.value.validate(async (valid) => {
    if (valid) {
      await Role.update(roleDTO.value)
      emits('success')
      cancelEdit()
    }
  })
}

// 提交
function submitData() {
  if (isEdit.value) {
    updateById()
  } else {
    add()
  }
}

// 修改权限
function submitAuthList() {
  Role.setAuth(roleDTO.value.id, roleDTO.value.authList).then(() => {
    // 验证当前用户是否为该角色, 如果是, 则需要删除权限，从后台重新获取并刷新整个路由
    if (user.roles.includes(roleDTO.value.roleCode)) {
      user.clearPermission().then(() => {
        permission.addRoutes.forEach((item) => {
          if (router.hasRoute(item.name)) {
            router.removeRoute(item.name)
          }
        })
        window.location.reload()
      })
    }
    cancelEdit()
  })
}

// 权限树组件
const authTreeRef = ref()

/**
 * 初始化角色下的所有权限
 * @param roleId 角色ID
 */
async function initRoleAuthList(roleId) {
  let { result } = await Role.authList(roleId)
  roleDTO.value.authList = result.map((i) => i.id)
  authListOfRole.value = result
}

// 弹框开关
const showDialog = ref(false)

// 设置权限的弹框开关
const showSetAuthDialog = ref(false)

// 是否编辑，false为新增弹框，true为编辑弹框
const isEdit = ref(false)

// 弹框标题
const title = computed(() => (isEdit.value ? '修改角色' : '新增角色'))

/**
 * 弹框的打开与关闭
 */
function switchDialog(role) {
  // 先判断是新增还是修改
  if (role) {
    isEdit.value = true
    roleDTO.value = Object.assign({}, role)
    initRoleAuthList(role.id)
  }
  showDialog.value = true
}

// 取消修改
function cancelEdit() {
  // 弹框关闭清空数据
  roleDTORef.value !== undefined && roleDTORef.value.resetFields()
  authTreeRef.value && authTreeRef.value.setCheckedKeys([])
  roleDTO.value.authList = []
  isEdit.value = false
  showDialog.value = false
  showSetAuthDialog.value = false
}

// 打开设置权限弹框
function openSetAuthDialog() {
  showDialog.value = false
  showSetAuthDialog.value = true
  nextTick(() => {
    // 权限树设置默认选中
    authListOfRole.value.forEach((item) => {
      let node = authTreeRef.value.getNode(item)
      if (node && node.isLeaf) {
        authTreeRef.value.setChecked(item, true)
      }
    })
  })
}

// 打开授权弹框
async function setAuth(role) {
  if (role) {
    isEdit.value = true
    roleDTO.value = Object.assign({}, role)
    await initRoleAuthList(role.id)
    openSetAuthDialog()
  }
}

defineExpose({ switchDialog, setAuth })
</script>

<style lang="scss" scoped>
.menu-tree {
  border-right: 3px solid var(--el-color-primary-light-7);
}
</style>
